<?php
/**
 * Nweb Framework
 *
 * This script is protected by copyright. It's use, copying, modification
 * and distribution without written consent of the author is prohibited.
 *
 * @category    source
 * @package     pl.nweb.framework.application
 * @author      Krzysztof Kardasz <krzysztof.kardasz@gmail.com>
 * @copyright   Copyright (c) 2011 Krzysztof Kardasz
 * @license     http://www.gnu.org/licenses/lgpl-3.0.txt  GNU Lesser General Public
 * @version     3.0 $Id: application.php 459 2012-01-11 15:46:03Z krzysztof.kardasz $
 * @link        http://code.google.com/p/nweb-framework/
 * @link        http://framework.nweb.pl
 */

namespace pl\nweb\framework;

/** @see \pl\nweb\framework\Exception **/
require_once __DIR__ . '/exception.php';

/** @see \pl\nweb\framework\application\Exception **/
require_once __DIR__ . '/application/exception.php';

/** @see \pl\nweb\framework\autoloader\Exception **/
require_once __DIR__ . '/autoloader/exception.php';

/** @see \pl\nweb\framework\autoloader\iAutoloader **/
require_once __DIR__ . '/autoloader/iautoloader.php';

/** @see \pl\nweb\framework\autoloader\Exception **/
require_once __DIR__ . '/autoloader/application.php';

/** @see \pl\nweb\framework\Autoloader **/
require_once __DIR__ . '/autoloader.php';

/**
 * Aplikacja
 *
 * Wczytanie konfiguracji, zdefiniowanie zasobów, uruchomienie
 *
 * @category    source
 * @package     pl.nweb.framework.application
 * @author      Krzysztof Kardasz <krzysztof.kardasz@gmail.com>
 * @copyright   Copyright (c) 2011 Krzysztof Kardasz
 * @version     3.0 $Id: application.php 459 2012-01-11 15:46:03Z krzysztof.kardasz $
 */
class Application
{
    /**
     * Bootstrap
     *
     * @var \pl\nweb\framework\application\Bootstrap
     */
    private $_bootstrap = null;

    /**
     * Środowisko
     *
     * @var string
     */
    private $_env = null;

    /**
     * Środowisko według nazwy hosta
     *
     * @var string|array
     */
    private $_envHost = null;

    /**
     * Środowisko według argumentu
     *
     * @var string
     */
    private $_envGetOpt = null;

    /**
     * Parametry
     */
    const PARAM_APPLICATION_PATH = 'application.path';
    const PARAM_ENV              = 'env';
    const PARAM_ENV_HOST         = 'env.host';
    const PARAM_ENV_GETOPT       = 'env.getopt';
    const PARAM_THROW_EXCEPTIONS = 'throw.exceptions';

    /**
     * Konstruktor
     *
     * @param  string $bootstrapClass klasa bootstrap
     * @throws \pl\nweb\framework\application\Exception
     */
    public function __construct (array $params = array())
    {
        if(isset($params[self::PARAM_THROW_EXCEPTIONS])) {
            $throwExceptions = (boolean)$params[self::PARAM_THROW_EXCEPTIONS];
        } else {
            $throwExceptions = true;
        }

        try {
            if(!isset($params[self::PARAM_APPLICATION_PATH])) {
                throw new application\Exception ('Param "' . self::PARAM_APPLICATION_PATH . '" is not defined');
            }
            if(isset($params[self::PARAM_ENV])) {
                $this->_env = $params[self::PARAM_ENV];
            }
            if(isset($params[self::PARAM_ENV_HOST])) {
                $this->_envHost = $params[self::PARAM_ENV_HOST];
            }
            if(isset($params[self::PARAM_ENV_GETOPT])) {
                $this->_envGetOpt = $params[self::PARAM_ENV_GETOPT];
            }

            define('APPLICATION_PATH', $params[self::PARAM_APPLICATION_PATH]);

            $pos       = strrpos(APPLICATION_PATH, DIRECTORY_SEPARATOR);
            $namespace = substr(APPLICATION_PATH, $pos+1);
            $autoloader = new autoloader\Application();
            $autoloader->addNamespace(
                $namespace,
                substr(APPLICATION_PATH, 0, $pos)
            );

            Autoloader::register($autoloader);

            $configManager = new \pl\nweb\framework\config\manager\Application (
                APPLICATION_PATH . DIRECTORY_SEPARATOR . 'configs',
                $this->_getEnv()
            );

            $bootstrapResource = new \pl\nweb\framework\application\resource\Bootstrap($configManager->getConfig('application')->get('bootstrap'));
            $bootstrapResource->setOption(array(
                \pl\nweb\framework\application\Bootstrap::OPTION_APPLICATION_NAMESPACE => $namespace,
                \pl\nweb\framework\application\Bootstrap::OPTION_APPLICATION_PATH      => APPLICATION_PATH,
                \pl\nweb\framework\application\Bootstrap::OPTION_AUTOLOADER            => $autoloader,
                \pl\nweb\framework\application\Bootstrap::OPTION_CONFIG_MANAGER        => $configManager
            ));
            $this->_bootstrap = $bootstrapResource->getObject();
        } catch (\Exception $e) {
            $msg = sprintf("%s: %s (%d)", $e->getMessage(), $e->getFile(), $e->getLine());
            error_log($msg, 0);
            trigger_error($msg, E_USER_ERROR);
            if($throwExceptions) {
                throw $e;
            }
        }
    }

    /**
     * Zwraca nazwę środowiska aplikacji
     *
     * @return false|string
     */
    protected function _getEnv ()
    {
        if(null === $this->_env) {
            if (isset($_SERVER['HTTP_HOST']) && $this->_envHost) {
                if(is_string($this->_envHost)) {
                    $file = APPLICATION_PATH . DIRECTORY_SEPARATOR . ltrim($this->_envHost, DIRECTORY_SEPARATOR);
                    if(is_file($file)) {
                        $this->_envHost = include $file;
                    } else {
                        throw new Exception ('Env host file "' . $file . '" not exists');
                    }
                }
                if(is_array($this->_envHost) && isset($this->_envHost[$_SERVER['HTTP_HOST']])) {
                    return $this->_env = $this->_envHost[$_SERVER['HTTP_HOST']];
                }
            } else if (isset($_SERVER['argc']) && $this->_envGetOpt) {
                if(strlen($this->_envGetOpt) > 1) {
                    $short = substr($this->_envGetOpt, 0, 1);
                    $long  = substr($this->_envGetOpt, 1);
                } else {
                    $short = $this->_envGetOpt;
                    $long  = null;
                }
                $options = getopt($short . ':', (($long) ? ($long . ':') : null));
                if(isset($options[$short])) {
                    return $this->_env = $options[$short];
                } else if ($long && isset($options[$long])) {
                    return $this->_env = $options[$long];
                }
            }
            $this->_env = false;
        }
        return $this->_env;
    }

    /**
     * Uruchamia aplikację
     *
     * @return void
     */
    public function run ()
    {
        $this->_bootstrap->boot();
    }
}